﻿using System;
using System.Linq.Expressions;
using System.Reflection;

namespace Postnuclear.Dependency.Visitors
  {
  /// <summary>
  /// Implements the visitor pattern to iterate through the expression tree.
  /// Takes the expression and simplify it.
  /// - if field used from constant it's replaced with constant.
  /// </summary>
  /// <remarks>
  /// This allows to remove anonymous classes usage from expression and fix strong referencing from such classes.
  /// </remarks>
  internal sealed class SimplifyExpressionVisitor
    : ExpressionVisitor
    {
    #region Protected

    // Methods

    /// <summary>
    /// Visits the children of the <see cref="T:System.Linq.Expressions.MemberExpression"/>.
    /// </summary>
    /// <param name="node">The expression to visit.</param>
    /// <returns>
    /// The modified expression, if it or any subexpression was modified; otherwise, returns the original expression.
    /// </returns>
    protected override Expression VisitMember(MemberExpression node)
      {
      if (node.Member.MemberType != MemberTypes.Property && (node.Expression == null || Visit(node.Expression).NodeType == ExpressionType.Constant))
        {
        // Field value can't be tracked + parent can't be changed => this is constant value for this expression
        return Visit(Expression.Constant(Expression.Lambda<Func<object>>(Expression.Convert(node, typeof(object))).Compile()()));
        }

      return base.VisitMember(node);
      }

    #endregion
    }
  }